from __future__ import division
from math import sqrt
from numpy import array
from scipy.optimize import fmin_l_bfgs_b
import pandas as pd
import matplotlib.pyplot as plt



# 求均方根误差
def RMSE(params, *args):

    # 从args中读取参数，Y为原始值列表，type为采用的季节性，有累加性和累乘性
    Y = args[0]
    type = args[1]
    rmse = 0

    alpha, beta, gamma = params
    m = args[2]
    a = [sum(Y[0:m]) / float(m)]
    b = [(sum(Y[m:2 * m]) - sum(Y[0:m])) / m ** 2]

    # 采用累加性的计算过程
    if type == 'additive':

        s = [Y[i] - a[0] for i in range(m)]
        y = [a[0] + b[0] + s[0]]

        for i in range(len(Y)):
            a.append(alpha * (Y[i] - s[i]) + (1 - alpha) * (a[i] + b[i]))
            b.append(beta * (a[i + 1] - a[i]) + (1 - beta) * b[i])
            s.append(gamma * (Y[i] - a[i] - b[i]) + (1 - gamma) * s[i])
            y.append(a[i + 1] + b[i + 1] + s[i + 1])

    # 采用累乘性的计算过程
    elif type == 'multiplicative':

        s = [Y[i] / a[0] for i in range(m)]
        y = [(a[0] + b[0]) * s[0]]

        for i in range(len(Y)):
            a.append(alpha * (Y[i] / s[i]) + (1 - alpha) * (a[i] + b[i]))
            b.append(beta * (a[i + 1] - a[i]) + (1 - beta) * b[i])
            s.append(gamma * (Y[i] / (a[i] + b[i])) + (1 - gamma) * s[i])
            y.append((a[i + 1] + b[i + 1]) * s[i + 1])

    # 求方差
    rmse = sqrt(sum([(m - n) ** 2 for m, n in zip(Y, y[:-1])]) / len(Y))

    return rmse

# 累乘性计算
def multiplicative(x, m, fc, alpha=None, beta=None, gamma=None):

    Y = x[:]

    if (alpha == None or beta == None or gamma == None):
        initial_values = array([0.0, 1.0, 0.0])
        boundaries = [(0, 1), (0, 1), (0, 1)]
        type = 'multiplicative'

        # 采用最小二乘法来做参数优化
        parameters = fmin_l_bfgs_b(RMSE, x0=initial_values, args=(Y, type, m), bounds=boundaries, approx_grad=True)
        alpha, beta, gamma = parameters[0]

    a = [sum(Y[0:m]) / float(m)]
    b = [(sum(Y[m:2 * m]) - sum(Y[0:m])) / m ** 2]
    s = [Y[i] / a[0] for i in range(m)]
    y = [(a[0] + b[0]) * s[0]]
    rmse = 0

    for i in range(len(Y) + fc):

        if i == len(Y):
            Y.append((a[-1] + b[-1]) * s[-m])

        a.append(alpha * (Y[i] / s[i]) + (1 - alpha) * (a[i] + b[i]))
        b.append(beta * (a[i + 1] - a[i]) + (1 - beta) * b[i])
        s.append(gamma * (Y[i] / (a[i] + b[i])) + (1 - gamma) * s[i])
        y.append((a[i + 1] + b[i + 1]) * s[i + 1])

    # 求均方根误差
    rmse = sqrt(sum([(m - n) ** 2 for m, n in zip(Y[:-fc], y[:-fc - 1])]) / len(Y[:-fc]))

    return Y[-fc:], alpha, beta, gamma, rmse

# 累加性计算
def additive(x, m, fc, alpha=None, beta=None, gamma=None):

    Y = x[:]

    if (alpha == None or beta == None or gamma == None):
        initial_values = array([0.1, 0.1, 0.1])
        boundaries = [(0, 1), (0, 1), (0, 1)]
        type = 'additive'
        # 采用最小二乘法来做参数优化
        parameters = fmin_l_bfgs_b(RMSE, x0=initial_values, args=(Y, type, m), bounds=boundaries, approx_grad=True)
        alpha, beta, gamma = parameters[0]

    a = [sum(Y[0:m]) / float(m)]
    b = [(sum(Y[m:2 * m]) - sum(Y[0:m])) / m ** 2]
    s = [Y[i] - a[0] for i in range(m)]
    y = [a[0] + b[0] + s[0]]
    rmse = 0

    for i in range(len(Y) + fc):

        if i == len(Y):
            Y.append(a[-1] + b[-1] + s[-m])
        a.append(alpha * (Y[i] - s[i]) + (1 - alpha) * (a[i] + b[i]))
        b.append(beta * (a[i + 1] - a[i]) + (1 - beta) * b[i])
        s.append(gamma * (Y[i] - a[i] - b[i]) + (1 - gamma) * s[i])
        y.append(a[i + 1] + b[i + 1] + s[i + 1])

    # 求均方根误差
    rmse = sqrt(sum([(m - n) ** 2 for m, n in zip(Y[:-fc], y[:-fc - 1])]) / len(Y[:-fc]))

    return Y[-fc:], alpha, beta, gamma, rmse

# 端口数据预测 datatype是需要预测的数据名，默认为ifInOctets（该端口输入字节数），type指采用的预测方案，默认为累乘性，prenum指要预测多少期数据，默认为10
def portDataPre(datatype='ifInOctets',port=1,type='multiplicative',prenum=10):
    # port_data.csv是从数据库中读出来的每个端口的数据，数据是我们实验中产生的，没有实际意义，所以此处只能做一个演示
    df = pd.read_csv("port_data.csv")
    df = df[df['port'] == port]
    data = df[datatype].values
    num = data.shape[0]
    # 此处的数值是一个累加量，将其转换为瞬时量
    for i in range(num - 1):
        data[i] = data[i + 1] - data[i]
    data=data[:-2]
    num=data.shape[0]
    data=list(data)
    if type=='multiplicative':
        result, alpha, beta, gamma, rmse = multiplicative(data, int(num / 2), prenum)
    else:
        result, alpha, beta, gamma, rmse = additive(data, int(num / 2), prenum)
    print(result)

# 协议数据预测 datatype是需要预测的数据名，默认为ipInReceives），type指采用的预测方案，默认为累乘性，prenum指要预测多少期数据，默认为10
def protocolDataPre(datatype='ipInReceives',type='multiplicative',prenum=10):
    # shared_data.csv是从数据库中读出来的每个端口的数据，数据是我们实验中产生的，没有实际意义，所以此处只能做一个演示
    df = pd.read_csv("shared_data.csv")
    data = df[datatype].values
    num = data.shape[0]
    # 此处的数值是一个累加量，将其转换为瞬时量
    for i in range(num - 1):
        data[i] = data[i + 1] - data[i]
    data=data[:-2]
    num=data.shape[0]
    data=list(data)
    if type=='multiplicative':
        result, alpha, beta, gamma, rmse = multiplicative(data, int(num / 2), prenum)
    else:
        result, alpha, beta, gamma, rmse = additive(data, int(num / 2), prenum)
    print(result)

if __name__ == '__main__':
    '''
    df = pd.read_csv("port_data.csv")
    # 此处用端口1的输入字节数作为测试数据,因为其余端口没有数据
    df = df[df['port'] == 1]
    ifInOctets = df['ifInOctets'].values
    num = ifInOctets.shape[0]
    # 此处的字节数是一个累加量，将其转换为瞬时量
    for i in range(num - 1):
        ifInOctets[i] = ifInOctets[i + 1] - ifInOctets[i]
    ifInOctets = ifInOctets[:-2]
    num = ifInOctets.shape[0]
    ifInOctets = list(ifInOctets)
    # 采用累加性
    result,alpha,beta,gamma,rmse=multiplicative(ifInOctets,int(num/2),100)
    print(result)
    for i in range(100):
        plt.scatter(i+1,result[i])
    plt.show()
    print(rmse)
  '''
    # 此处做了两个演示，函数都已给定默认参数
    portDataPre()
    protocolDataPre()

